using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.Design.WebControls;
using System.ComponentModel;
using System.Drawing;
using System.ComponentModel.Design;
using System.Web.UI.WebControls;
using System.Web.UI.Design;

namespace AjaxCtrlsExtenders
{
    internal class MultiSelectDropDownComboBoxDesigner : CompositeControlDesigner
    {
        MultiSelectDropDownComboBox box;

        public override void OnComponentChanged(Object sender, ComponentChangedEventArgs ce)
        {
            ComponentChangedEventArgs newArgs = ce;
            if (ce.Member.Name == "Width")
            {
                newArgs = updateWidth(sender, ce);
            }
            if (ce.Member.Name == "Height")
            {
                newArgs = updateHeight(sender, ce);
            }
            if (ce.Member.Name == "BackColor")
            {
                newArgs = updateBackColor(sender, ce);
            }
            if (ce.Member.Name == "ListboxVisible")
            {
                newArgs = updateListboxVisible(sender, ce);
            }

            base.OnComponentChanged(sender, newArgs);
        }
        private ComponentChangedEventArgs updateListboxVisible(Object sender, ComponentChangedEventArgs ce)
        {
            //PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(box);
            //System.ComponentModel.PropertyDescriptor myProperty;
            //myProperty = properties.Find("ListboxVisible", false);
            //myProperty.SetValue(box, (bool)ce.NewValue);
            return ce;
        }
        private ComponentChangedEventArgs updateHeight(Object sender, ComponentChangedEventArgs ce)
        {
            // if we have no values, just return default args
            if (((Unit)ce.NewValue).IsEmpty || ((Unit)ce.OldValue).IsEmpty)
            {
                return ce;
            }

            double newHeight = ((Unit)ce.NewValue).Value;
            double oldHeight = ((Unit)ce.OldValue).Value;

            double difference = newHeight - oldHeight;
            if (box.TextboxHeight.Value + difference < 0)
            {
                throw new ArgumentOutOfRangeException("Height is to small.");
            }
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(box);
            // property descriptor object
            System.ComponentModel.PropertyDescriptor myProperty;
            //// Sets an PropertyDescriptor to the specific property.
            // get specific property (case insensitive search
            myProperty = properties.Find("TextboxHeight", false);
            // set the specified property on the proper component
            myProperty.SetValue(box, new Unit(box.TextboxHeight.Value + difference, UnitType.Pixel));

            return ce;
        }


        private ComponentChangedEventArgs updateBackColor(Object sender, ComponentChangedEventArgs ce)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(box);
            System.ComponentModel.PropertyDescriptor myProperty;
            myProperty = properties.Find("TextboxBackColor", false);
            myProperty.SetValue(box, (Color)ce.NewValue);
            myProperty = properties.Find("ListboxBackColor", false);
            myProperty.SetValue(box, (Color)ce.NewValue);
            myProperty = properties.Find("ButtonBackColor", false);
            myProperty.SetValue(box, (Color)ce.NewValue);
            return ce;
        }

        private ComponentChangedEventArgs updateWidth(Object sender, ComponentChangedEventArgs ce)
        {
            // TODO: If the value is to small, it throws an error
            // however, after the error, this method is called again because the value is reset
            // from the invalid value to the original value thereby causing all the updates a second time
            // but because the error existed in the first place it seems the udpates are not actually made
            // to the other control property values and they get out of sync. How do I fix this?
            // for now, do not make the control smaller than the button width plus 7! Default min would be 39px


            // if we have no values, just return default args
            if (((Unit)ce.NewValue).IsEmpty || ((Unit)ce.OldValue).IsEmpty)
            {
                return ce;
            }

            double newWidth = ((Unit)ce.NewValue).Value;
            double oldWidth = ((Unit)ce.OldValue).Value;

            double difference = newWidth - oldWidth;


            // to set other properties correctly, we must use the property descriptor objects and set them
            // otherwise if we set the property on the object directly, it does not persist the changes
            // and we lose the information.
            // get the property colleciton of the control
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(box);
            // property descriptor object
            System.ComponentModel.PropertyDescriptor myProperty;
            //// Sets an PropertyDescriptor to the specific property.
            // get specific property (case insensitive search
            myProperty = properties.Find("TextboxWidth", false);
            // set the specified property on the proper component
            myProperty.SetValue(box, new Unit(box.TextboxWidth.Value + difference, UnitType.Pixel));

            myProperty = properties.Find("ListboxWidth", false);
            myProperty.SetValue(box, new Unit(box.ListboxWidth.Value + difference, UnitType.Pixel));

            // if the control is too small throw an error
            if (newWidth < box.ButtonWidth.Value + 7)
            {
                throw new ArgumentOutOfRangeException("Control cannot be that small.");
            }

            // return the updated values
            return new ComponentChangedEventArgs(box, ce.Member, ce.OldValue, new Unit(newWidth, UnitType.Pixel));

        }

        MultiSelectDropDownComboBoxDesigner() 
        {
        }

        public override bool AllowResize
        {
            get
            {
                return base.AllowResize;
            }
        }
        public override void InitializeNewComponent(System.Collections.IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);
        }
        public override string GetDesignTimeHtml(System.Web.UI.Design.DesignerRegionCollection regions)
        {
            //regions.Add(new DesignerRegion(this, "Textbox"));
            //regions.Add(new DesignerRegion(this, "Button"));
            //regions.Add(new DesignerRegion(this, "Listbox"));
            return base.GetDesignTimeHtml(regions);
        }

        public override string GetDesignTimeHtml()
        {
            return base.GetDesignTimeHtml();
        }
        protected override string GetErrorDesignTimeHtml(Exception e)
        {
            return base.GetErrorDesignTimeHtml(e);
        }
        protected override string GetEmptyDesignTimeHtml()
        {
            return base.GetEmptyDesignTimeHtml();
        }

        public override void Initialize(IComponent component)
        {
            if (!(component is MultiSelectDropDownComboBox))
            {
                throw new ArgumentException("Must be a MutliSelectDropDownComboBox", "component");
            }
            box = (MultiSelectDropDownComboBox)component;
            box.Width = new Unit(MultiSelectDropDownComboBox.defaultWidth, UnitType.Pixel);
            box.TextboxWidth = new Unit(MultiSelectDropDownComboBox.defaultTextboxWidth, UnitType.Pixel);
            box.ButtonWidth = new Unit(MultiSelectDropDownComboBox.defaultButtonWidth, UnitType.Pixel);
            box.ListboxWidth = new Unit(MultiSelectDropDownComboBox.defaultListboxWidth, UnitType.Pixel);

            base.Initialize(component);
        }
        protected override void OnClick(System.Web.UI.Design.DesignerRegionMouseEventArgs e)
        {
            base.OnClick(e);
        }
    }
}
